import "dayjs/locale/zh-cn";

import dayjs, { type UnitType } from "dayjs";
import relativeTime from "dayjs/plugin/relativeTime";
import timezone from "dayjs/plugin/timezone";
import utc from "dayjs/plugin/utc";

dayjs.locale("zh-cn");
dayjs.extend(relativeTime);
dayjs.extend(utc);
dayjs.extend(timezone);
dayjs.tz.setDefault("PRC");

export class DateTimeUtils {
    /**
     * 获取当前日期和时间的格式化字符串或者部分信息
     * @param format 格式化字符串
     * @param unit 时间单位（年、月、日、小时、分钟、秒）
     * @returns 当前日期和时间格式化后的字符串或者部分时间信息
     * @example
     * getCurrentDateTime(undefined, "month") // 8
     */
    static getCurrentDateTime(
        format: string = "YYYY-MM-DD HH:mm:ss",
        unit: "year" | "month" | "day" | "hour" | "minute" | "second" | "all" = "all"
    ): string | number {
        // const year = dayjs().year();
        // const month = dayjs().month() + 1; // 注意月份是从0开始的
        // const day = dayjs().date();
        // const hour = dayjs().hour();
        // const minute = dayjs().minute();
        if (unit === "month") return dayjs().month() + 1;
        return unit === "all" ? dayjs().tz().format(format) : dayjs()[unit]();
    }

    /**
     * 格式化给定的日期时间字符串
     * @param dateTime 日期时间字符串
     * @param format 格式化字符串
     * @returns 格式化的日期时间字符串
     */
    static formatDateTime(dateTime: string, format: string = "YYYY-MM-DD HH:mm:ss"): string {
        return dayjs.tz(dateTime).format(format);
    }

    /**
     * 解析日期时间字符串为 Day.js 实例
     * @param dateTime 日期时间字符串
     * @returns Day.js 实例
     */
    static parseDateTime(dateTime: string): dayjs.Dayjs {
        return dayjs.tz(dateTime);
    }

    /**
     * 获取两个日期之间的差值 endDate - startDate
     * @param startDate 开始日期
     * @param endDate 结束日期
     * @param unit 时间单位（年、月、日、小时、分钟、秒）
     * @returns 差值。差值结果带有正负
     * @example
     * getDifference("2023-01-02 00:00:00", "2023-01-01 00:00:00", "day") // -1
     */
    static getDifference(
        startDate: string,
        endDate: string,
        unit: "year" | "month" | "day" | "hour" | "minute" | "second" = "day"
    ): number {
        return dayjs(endDate).diff(dayjs(startDate), unit);
    }

    /**
     * 获取日期的相对当前时间的描述
     * @param dateTime 日期时间字符串
     * @returns 相对时间描述
     * @example
     * getRelativeTime("2023-01-01 00:00:00") // "1 年前"
     */
    static getRelativeTime(dateTime: string): string {
        return dayjs.tz(dateTime).fromNow();
    }

    /**
     * 比较日期：判断给定日期是否在今天之前
     * @param dateTime 日期时间字符串
     * @returns boolean
     * @example
     * isBeforeToday("2023-01-01 00:00:00") // true
     */
    static isBeforeToday(dateTime: string): boolean {
        return dayjs.tz(dateTime).isBefore(dayjs());
    }

    /**
     * 根据当前日期获取之前或之后的日期
     * @param offset 偏移量
     * @param unit 时间单位（默认为 'day'）
     * @returns string 年月日
     * @example
     * // 当前日期： "2023-01-02"
     * getOffsetDate(1, "day") // "2023-01-03"
     * getOffsetDate(-1, "day") // "2023-01-01"
     */
    static getOffsetDate(offset: number, unit: "year" | "month" | "day" | "hour" | "minute" | "second" = "day") {
        return dayjs().tz().add(offset, unit).format("YYYY-MM-DD");
    }

    /**
     * 固定部分日期和时间信息
     * @param options 要设置的时间部分选项
     * @param dateTime 日期时间字符串，默认为当前日期和时间
     * @returns string
     * @example
     * 比如要得到当日日期的 12:30 字符串。其他时间部分如年月日秒为当前时间
     * setDateTime({ hour: 12, minute: 30 }) // "2024-08-19 12:30:52"
     */
    static setDateTime(
        options: Partial<Record<"year" | "month" | "day" | "hour" | "minute" | "second", number>>,
        dateTime?: string | dayjs.Dayjs,
        format: string = "YYYY-MM-DD HH:mm:ss"
    ): string {
        let date = dateTime ? dayjs(dateTime) : dayjs();
        for (const key in options) {
            // eslint-disable-next-line no-prototype-builtins
            if (options.hasOwnProperty(key)) {
                // @ts-ignore
                date = date.set(key as UnitType, options[key]);
            }
        }
        return date.format(format);
    }
}
